package Client.View;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.JPanel;

import Client.Model.GameModel;
import Ships.Ship;

import logic.Board;

@SuppressWarnings("serial")
class ConfigBoardCanvas extends JPanel implements MouseListener, MouseMotionListener, KeyListener{
	
	/**
	 * 
	 */
	
	private final static int BOARD_SQUARE_SIZE = 30;
	
	private final static int BOARD_BASE_X = 20;
	private final static int BOARD_BASE_Y = 10;
	
	private final static int AV_SHIPS_BASE_X = 350;
	private final static int AV_SHIPS_BASE_Y = 10;
	
	GameModel model;
	Board board;
	int width;
	int height;
	
	ArrayList<Ship> availableShips = new ArrayList<Ship>();
	
	boolean selected = false;
	Ship selectedShip = null;
	int currentX=0;
	int currentY=0;
	
	public ConfigBoardCanvas(GameModel model, int width, int height) {
	
		this.model = model;
		this.board = model.getBoard();
		this.height = height;
		this.width = width;
		
		this.setBackground(LoginFrame.DEFAULT_BG_COLOR);
		setPreferredSize(new Dimension(width, height));

		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		this.addKeyListener(this);
		
		setOpaque(false);
		
		this.setFocusable(true);
	
		if (board!=null)
			updateAvailableShips();
				
	}
	

	private void updateAvailableShips(){
		
		availableShips.clear();
		
		for (Ship p : board.getShips())
			if (!p.isAtBoard(board) || !p.isWellPositioned(board)){
				availableShips.add(p);
				p.setOrientation(Ship.HORIZONTAL);
			}
		
	}
	
	@Override
	public void paintComponent(Graphics g) {
		        
	    super.paintComponent(g);
	    		
	    board = model.getBoard();
		if (board!=null)
			updateAvailableShips();
		else
			return;
	    
		
		paintBoard(g);
				
		paintShips(g);
			
		paintAvailableShips(g);
		
		paintSelected(g);
	
	    
		
	}
	
	private void paintSelected(Graphics g){
			
		if (selected && selectedShip!=null){
			
			int line = getLine(currentY);
			int col = getColumn(currentX);
			
			selectedShip.setCol_ini(col);
			selectedShip.setLin_ini(line);
			
			if (selectedShip.isAtBoard(board)){
				currentX = getX(col);
				currentY = getY(line);
				
				if (selectedShip.isWellPositioned(board))
					drawShip(g, selectedShip, currentX, currentY, Color.GREEN);
				else
					drawShip(g, selectedShip, currentX, currentY, Color.RED);
				
			}
			else
				drawShip(g, selectedShip, currentX, currentY, Color.ORANGE);
			
			
			
			if (!selectedShip.isWellPositioned(board)){
				selectedShip.setCol_ini(-1);
				selectedShip.setLin_ini(-1);
			}
			
		}
		
	}
	
	private void paintShips(Graphics g) {
				
		for (Ship ship: board.getShips())
			if (!availableShips.contains(ship))
				drawShip(g, ship, getX(ship.getCol_ini()), getY(ship.getLin_ini()), Color.BLUE);
		
	}

	private void paintAvailableShips(Graphics g){

		int i=0;
		
		for (Ship ship: availableShips){
			
			if (!selected || selectedShip!=ship )
				drawShip(g, ship, getAvailableX(i), getAvailableY(i), Color.ORANGE);

			i++;
		}

		
	}
	
	private void drawShip(Graphics g, Ship ship, int x, int y, Color c){
		
		g.setColor(c);
		
		if (ship.getOrientation()==Ship.HORIZONTAL){
			
			g.fillRect(x+1, y+1, BOARD_SQUARE_SIZE * ship.getSize() - 2, BOARD_SQUARE_SIZE - 2);
			
			g.setColor(Color.BLACK);
			g.drawRect(x+1, y+1, BOARD_SQUARE_SIZE * ship.getSize() - 2, BOARD_SQUARE_SIZE - 2);
		}
		else{
			g.fillRect(x+1, y+1, BOARD_SQUARE_SIZE -2, BOARD_SQUARE_SIZE * ship.getSize() -2);
			
			g.setColor(Color.BLACK);
			g.drawRect(x+1, y+1, BOARD_SQUARE_SIZE -2, BOARD_SQUARE_SIZE * ship.getSize() -2);
		}
		
	}

	private void paintBoard(Graphics g) {
		
		//draw border
		g.setColor(Color.BLACK);
		g.drawRect(BOARD_BASE_X, BOARD_BASE_Y, BOARD_SQUARE_SIZE * board.getNColumns(), BOARD_SQUARE_SIZE * board.getNLines());
		
		//draw background
		g.setColor(Color.CYAN);
		g.fillRect(BOARD_BASE_X, BOARD_BASE_Y, BOARD_SQUARE_SIZE * board.getNColumns(), BOARD_SQUARE_SIZE * board.getNLines());
		
		
		g.setColor(Color.GRAY);
		
		//draw vertical lines
		for (int i=0; i<board.getNColumns(); i++)
			g.drawLine(getX(i), BOARD_BASE_Y, getX(i), getY(board.getNLines()));
		
		//draw horizontal lines
		for (int i=0; i<board.getNLines(); i++)
			g.drawLine(BOARD_BASE_X, getY(i), getX(board.getNColumns()), getY(i));
			
		
		
	}

	int getX(int column){
		
		return BOARD_BASE_X + (column*BOARD_SQUARE_SIZE);
		
	}
	
	int getY(int line){
		
		return BOARD_BASE_Y + (line*BOARD_SQUARE_SIZE);
	}
	
	int getLine(int Y){

		Y -= BOARD_BASE_Y;
		return Y/BOARD_SQUARE_SIZE;

	}
	
	int getColumn(int X){
		
		X -= BOARD_BASE_X;
		return X/BOARD_SQUARE_SIZE;
	}

	int getAvailableY(int index){
		return AV_SHIPS_BASE_Y + index*(BOARD_SQUARE_SIZE + 10);
	}
	
	int getAvailableX(int index){
		return AV_SHIPS_BASE_X;
	}
	
	
	private Ship getSelectedAvailableShip(int x, int y){
		
		if (x<AV_SHIPS_BASE_X || y<AV_SHIPS_BASE_Y)
			return null;
		
		x -= AV_SHIPS_BASE_X;
		y-= AV_SHIPS_BASE_Y;
		
		int index = y/(BOARD_SQUARE_SIZE+10);
				
		if (index>=0 && index<availableShips.size()){
			Ship s = availableShips.get(index);
			
			if (x<= s.getSize()*BOARD_SQUARE_SIZE)
				return s;
			
		}
			
		System.out.println("null");
		
		return null;
	}

	
	//--------- Mouse Listeners ----------
			

	@Override
	public void mouseClicked(MouseEvent e) {

	}

	@Override
	public void mouseEntered(MouseEvent e) {
		
		 requestFocus();
	}

	@Override
	public void mouseExited(MouseEvent e) {
	}

	@Override
	public void mousePressed(MouseEvent e) {
		
		Ship s;
		
		if (!selected){
		
		s = getSelectedAvailableShip(e.getX(), e.getY());
		
		if (s==null){
			
			int line = getLine(e.getY());
			int col = getColumn(e.getX());
			
			s = board.getShipAt(line, col);
			
			if (s!=null){
				//System.out.println("SHIP RELOCATE: " + s);
				availableShips.add(s);
				s.setCol_ini(-1);
				s.setLin_ini(-1);
			}
		
		}
		//else
			//System.out.println("SHIP PUT");
		
		
		
		if (s!=null){
		
			selected = true;
			selectedShip = s;
			currentX = e.getX();
			currentY = e.getY();
			
		}
		else
			System.out.println("NULL");
		
		repaint();
		
		}
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		
		updateAvailableShips();
		
		if (selected){
			
			int line = getLine(e.getY());
			int col = getColumn(e.getX());

			//System.out.println("line: " + line + "  col: " + col);
			
			selectedShip.setCol_ini(col);
			selectedShip.setLin_ini(line);
			
			if (selectedShip.isWellPositioned(board))
				availableShips.remove(selectedShip);
			else
				selectedShip.setCol_ini(-1);

			selected = false;
			selectedShip = null;

			repaint();

		}
		
	}


	@Override
	public void mouseDragged(MouseEvent e) {
		
		currentX = e.getX();
		currentY = e.getY();
			
		if (selected)	
			repaint();
		
	}


	@Override
	public void mouseMoved(MouseEvent e) {
		
	}

	
	
	/*-- KEY Listeners --*/

	@Override
	public void keyPressed(KeyEvent e) {
		
		if (selected)
			if (e.getKeyChar()=='r' || e.getKeyChar()=='R'){
				System.out.println("R");
				selectedShip.switchOrientation();
				repaint();
			}
			
	}


	@Override
	public void keyReleased(KeyEvent e) {}


	@Override
	public void keyTyped(KeyEvent e) {}
		
}